package com.ruoyi.web.admin.data;

import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.web.admin.data.command.CommandHandler;
import com.ruoyi.web.admin.data.command.CommandHandlerFactory;
import com.ruoyi.web.admin.data.utils.AESUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Objects;

/**
 * @author 10100
 */
@ChannelHandler.Sharable
@Component
public class TcpServerHandler extends SimpleChannelInboundHandler<String> {

    private static final Logger log = LoggerFactory.getLogger(TcpServerHandler.class);

    private final CommandHandlerFactory commandHandlerFactory;

    public TcpServerHandler() {
        commandHandlerFactory = SpringUtils.getBean(CommandHandlerFactory.class);
    }

    private String deviceId;

    @Value(value = "${device.health.interval:1}")
    private String healthInterval;

    @Value(value = "${device.location.mode:3}")
    private String locationMode;


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) {
        log.debug("收到加密数据：{}", msg);
        try {
            String decrypted = AESUtils.decrypt(msg);
            log.debug("解密后：{}", decrypted);
            Channel channel = ctx.channel();
            String response = handleMessage(channel, decrypted);
            log.debug("发送加密前数据：{}", response);
            String encryptMsg = AESUtils.encrypt(response);
            if (Objects.nonNull(encryptMsg)) {
                ctx.writeAndFlush(encryptMsg);
                log.debug("发送加密数据: {}", encryptMsg);
            }
        } catch (Exception e) {
            // 定义日志文件路径（可以根据需要修改）
            String filePath = "command_error_log.txt";
            String logMessage = "处理失败" + "    " + msg + "\n";
            // true 表示追加模式
            try (FileWriter writer = new FileWriter(filePath, true)) {
                writer.write(logMessage);
            } catch (IOException exception) {
                log.error("写入日志文件失败：", exception);
            }
        }
    }

    private String handleMessage(Channel channel, String rawMessage) {
        if (StringUtils.isEmpty(rawMessage) || !rawMessage.startsWith("[") || !rawMessage.endsWith("]")) {
            return "";
        }

        // 去除头尾
        String messageContent = rawMessage.substring(1, rawMessage.length() - 1);
        String[] parts = messageContent.split(",", 8);
        if (parts.length < 8) {
            return "";
        }
        //设备号
        this.deviceId = parts[0];
        //SIM 卡 ICCID
        String iccid = parts[1];
        //交易流水号  时间格式+4 位循环数
        String recordId = parts[2];
        String command = parts[3];
        // 1:下发请求,2. 下发响应 3:上报请求 4.上报响应
        String type = parts[4];
        String timestamp = parts[5];
        String length = parts[6];
        String body = parts[7];

        if (Objects.equals(command, "DEVICE_LOGIN")) {
            // 将当前处理器添加到设备映射中
            DeviceChannelInfo deviceChannelInfo = new DeviceChannelInfo();
            deviceChannelInfo.setDeviceId(deviceId);
            deviceChannelInfo.setChannel(channel);
            deviceChannelInfo.setConnectTime(System.currentTimeMillis());
            deviceChannelInfo.setIccid(iccid);
            DeviceSocketManager.addClient(deviceId, deviceChannelInfo);
            channel.attr(AttributeKey.valueOf("deviceId")).set(deviceId);
            log.info("设备[{}]TCP连接已建立", deviceId);

            String commandStr = CommandMessageBuilder.buildLocationModeSetMessage(deviceId, iccid, locationMode);
            channel.writeAndFlush(AESUtils.encrypt(commandStr));

            commandStr = CommandMessageBuilder.buildHealthIntervalMessage(deviceId, iccid, healthInterval);
            channel.writeAndFlush(AESUtils.encrypt(commandStr));
        }

        if (Objects.equals(command, "REPORT_LOCATION_INFO")) {
            // 定义日志文件路径（可以根据需要修改）
            String filePath = "command_log.txt";
            String logMessage = deviceId + "    " + rawMessage + "\n";
            // true 表示追加模式
            try (FileWriter writer = new FileWriter(filePath, true)) {
                writer.write(logMessage);
            } catch (IOException exception) {
                log.error("写入日志文件失败：", exception);
            }
        }

        // 获取对应的命令处理器并处理命令
        CommandHandler handler = commandHandlerFactory.getHandler(command);
        if (handler == null) {
            return "";
        }
        return handler.handle(deviceId, iccid, recordId, command, type, timestamp, length, body);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("客户端建立连接：{}", ctx.channel().remoteAddress());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("通信异常：{}, remote addr: {}", deviceId, ctx.channel().remoteAddress(), cause);
        DeviceSocketManager.removeClient(deviceId);
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        DeviceSocketManager.removeClient(deviceId);
        log.warn("设备[{}]连接已断开, remote addr: {}", deviceId, ctx.channel().remoteAddress());
    }
}